﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Reflection;

namespace HF.Repository.MSSql
{
    public class SqlSyntaxHelper
    {
        public virtual string GetDistinctKeyword()
        {
            return "DISTINCT";
        }

        public virtual string GetFirstKeyword()
        {
            return "TOP 1";
        }

        public virtual string GetAverageKeyword()
        {
            return "AVG";
        }

        public virtual string GetCountKeyword()
        {
            return "COUNT(*)";
        }

        public virtual string GetMaxKeyword()
        {
            return "MAX";
        }

        public virtual string GetMinKeyword()
        {
            return "MIN";
        }

        public virtual string GetSumKeyword()
        {
            return "SUM";
        }

        public virtual string GetInnerJoinKeyword()
        {
            return "INNER JOIN";
        }

        public virtual string GetCrossJoinKeyword()
        {
            return "CROSS JOIN";
        }

        public virtual string GetLengthKeyword()
        {
            return "LEN";
        }

        public virtual string GetSubstringKeyword()
        {
            return "SUBSTRING";
        }

        public virtual string GetUpperKeyword()
        {
            return "UPPER";
        }

        public virtual string GetLowerKeyword()
        {
            return "LOWER";
        }

        public virtual string GetDateTimeKeyword(string property)
        {
            switch (property)
            {
                case "Year":
                    return "yyyy";
                case "Month":
                    return "mm";
                case "Day":
                    return "dd";
                case "DayOfYear":
                    return "dy";
                case "Hour":
                    return "hh";
                case "Minute":
                    return "mi";
                case "Second":
                    return "ss";
                case "Millisecond":
                    return "ms";
                default:
                    throw new ArgumentException();
            }
        }

        public virtual string GetWildCard()
        {
            return "%";
        }

        public virtual string GetSetOperationKeyword(string operation)
        {
            switch (operation)
            {
                case "Concat":
                    return "UNION ALL";
                case "Except":
                    return "EXCEPT";
                case "Intersect":
                    return "INTERSECT";
                case "Union":
                    return "UNION";
                default:
                    throw new ArgumentException();
            }
        }

        public virtual string GetIsNullKeyword()
        {
            return "ISNULL";
        }

        public virtual string GetStringMethod(MethodInfo method, string[] operands)
        {
            string wildCard = "'" + GetWildCard() + "'";

            switch (method.Name)
            {
                case "StartsWith":
                    Debug.Assert(operands.Length == 2);
                    return operands[0] + " Like (" + operands[1] + " + " + wildCard + ")";
                case "EndsWith":
                    Debug.Assert(operands.Length == 2);
                    return operands[0] + " Like (" + wildCard + " + " + operands[1] + ")";
                case "Contains":
                    Debug.Assert(operands.Length == 2);
                    ;
                    return operands[0] + " Like (" + wildCard + " + " + operands[1] + " + " + wildCard + ")";
                case "Substring":
                    Debug.Assert(operands.Length == 3); // should throw an error instead
                    return GetSubstringKeyword() +
                           "(" + operands[0] + ", " + operands[1] + ", " + operands[2] + ")";
                case "ToUpper":
                    Debug.Assert(operands.Length == 1);
                    return GetUpperKeyword() + "(" + operands[0] + ")";
                case "ToLower":
                    Debug.Assert(operands.Length == 1);
                    return GetUpperKeyword() + "(" + operands[0] + ")";
                default:
                    return method.Name + " Has no translation to SQL.";
            }
        }

        public virtual string GetLengthProperty(string memberName)
        {
            return GetLengthKeyword() + "(" + memberName + ")";
        }

        public virtual string GetDateTimeProperty(string memberName, string datePart)
        {
            return "datePart(" + GetDateTimeKeyword(datePart) + ", " + memberName + ")";
        }

        public virtual bool CanOrderOnAliasedAggregate()
        {
            return true;
        }
    }
    /*
    public class AccessSyntaxHelper : SqlSyntaxHelper
    {
        public override string GetCrossJoinKeyword()
        {
            return ",";
        }

        public override string GetSubstringKeyword()
        {
            return "MID$";
        }

        public override string GetDateTimeKeyword(string property)
        {
            return "\"" + base.GetDateTimeKeyword(property) + "\"";
        }

        public override bool CanOrderOnAliasedAggregate()
        {
            return false;
        }
    }

    public class SQLiteSyntaxHelper : SqlSyntaxHelper
    {
        public override string GetLengthKeyword()
        {
            return "LENGTH";
        }

        public override string GetSubstringKeyword()
        {
            return "SUBSTR";
        }

        public override string GetDateTimeKeyword(string property)
        {
            switch (property)
            {
                case "Year":
                    return "'%Y'";
                case "Month":
                    return "'%m'";
                case "Day":
                    return "'%d'";
                case "DayOfYear":
                    return "'%j'";
                case "Hour":
                    return "'%H'";
                case "Minute":
                    return "'%M'";
                case "Second":
                    return "'%S'";
                case "Millisecond":
                    return "'%f'";
                default:
                    throw new ArgumentException();
            }
        }

        public override string GetIsNullKeyword()
        {
            return "IFNULL";
        }

        public override string GetStringMethod(MethodInfo method, List<string> operands)
        {
            string wildCard = "'" + GetWildCard() + "'";

            switch (method.Name)
            {
                case "StartsWith":
                    Debug.Assert(operands.Count == 2);
                    return "Like (" + operands[1] + " || " + wildCard + ", " + operands[0] + ")";
                case "EndsWith":
                    Debug.Assert(operands.Count == 2);
                    return "Like (" + wildCard + " || " + operands[1] + ", " + operands[0] + ")";
                case "Contains":
                    Debug.Assert(operands.Count == 2);
                    ;
                    return "Like (" + wildCard + " || " + operands[1] + " || " + wildCard + ", " + operands[0] + ")";
                case "Substring":
                    Debug.Assert(operands.Count == 3); // should throw an error instead
                    return GetSubstringKeyword() +
                           "(" + operands[0] + ", " + operands[1] + ", " + operands[2] + ")";
                case "ToUpper":
                    Debug.Assert(operands.Count == 1);
                    return GetUpperKeyword() + "(" + operands[0] + ")";
                case "ToLower":
                    Debug.Assert(operands.Count == 1);
                    return GetLowerKeyword() + "(" + operands[0] + ")";
                default:
                    return method.Name + " Has no translation to SQL.";
            }
        }

        public override string GetDateTimeProperty(string memberName, string datePart)
        {
            return "round(strftime(" + GetDateTimeKeyword(datePart) + ", " + memberName + "))";
        }
    }
    */

}